/*
 * Created by SharpDevelop.
 * User: fatman
 * Date: 10/27/2008
 * Time: 3:36 AM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;


namespace CUALib
{
	/// <summary>
	/// Description of PanelBase.
	/// </summary>
	
	public class PanelBase : ConsoleControl
	{

		public PanelBase(bool consoleExists)
			: base(consoleExists)
		{
			_textLines = new List<KeyValuePair<Point, string>>();
			MakeScrollBars(consoleExists);
		}

		

		#region private
		IList<KeyValuePair<Point, string>> _textLines;
		IList<string> _textLinesWrap;
		
		Point _textStartPos = new Point(0, 1);
		Point _lineShift = new Point(0, 1);
		#endregion

		#region prop
		private Point _location;
		public override Point Location
		{
			get { return _location; }
			set
			{
				if (_location != value)
				{
					if (CanChangeLocationSize(value, _size))
					{
						//Point oldLoc = _location;

						Rectangle invalidateRect = this.AbsoluteBounds;
						_location = value;
						CreateFinalStringList();
						Redraw();
						if (Parent != null)
							Parent.Invalidate(invalidateRect);

						//Console.MoveBufferArea(oldLoc.X, oldLoc.Y, _size.Width + 1, _size.Height + 1, _location.X, _location.Y);
					}
				}

			}
		}

		private Size _size;
		public override Size Size
		{
			get { return _size; }
			set
			{
				if (_size != value)
				{
					if (CanChangeLocationSize(Location, value))
					{
						Rectangle invalidateRect = this.AbsoluteBounds;
						_size = value;
						CreateFinalStringList();
						Redraw();
						if (Parent != null)
							Parent.Invalidate(invalidateRect);
					}
				}
			}
		}






		private string _text = String.Empty;
		public virtual string Text
		{
			get
			{
				return _text;
			}
			set
			{
				if (_text != value)
				{
					_text = value;
					CreateFinalStringList();
				}
			}
		}

		private string _title = String.Empty;
		public string Title
		{
			get { return _title; }
			set
			{
				if (_title != value)
				{
					_title = value;
					CreateFinalStringList();
					Redraw();
				}

			}
		}

		#endregion

		private bool CanChangeLocationSize(Point loc, Size siz)
		{
			if (!ConsoleExists)
				return true;

			if (((loc.X + siz.Width) >= Console.BufferWidth) || ((loc.Y + siz.Height) >= Console.BufferHeight) || (loc.X < 0) || (loc.Y < 0))
			{
				return false;
			}
			return true;
		}

		private string CreateTopBorder()
		{
			if (_size.Width == 0)
				return "";

			int titlePad = 2;
			int titleMaxLen = _size.Width - 2 * titlePad;
			string title = _title;

			//make ellipse
			if (_title.Length > titleMaxLen)
			{
				if (titleMaxLen > 6)
					title = title.Substring(0, titleMaxLen - 3) + "...";
				else if (title.Length >= 3)
					title = title.Substring(0, 3);

			}

			StringBuilder sb = new StringBuilder();
			sb.Append(base.DecorationSet [BoxDrawingDecorationNames.cornerLT]);
			sb.Append(base.DecorationSet [BoxDrawingDecorationNames.horizontalTop], titlePad);


			sb.Append(title);


			sb.Append(base.DecorationSet [BoxDrawingDecorationNames.horizontalTop], _size.Width - sb.Length);
			sb.Append(base.DecorationSet [BoxDrawingDecorationNames.cornerRT]);
			return sb.ToString();
		}

		private string CreateBottomBorder()
		{
			if (_size.Width == 0)
				return "";

			StringBuilder sb = new StringBuilder();
			sb.Append(base.DecorationSet [BoxDrawingDecorationNames.cornerLB]);
			sb.Append(base.DecorationSet [BoxDrawingDecorationNames.horizontalBottom], _size.Width - 1);
			sb.Append(base.DecorationSet [BoxDrawingDecorationNames.cornerRB]);
			return sb.ToString();
		}

		/*private void CreateFinalStringList()
		{
			CreateStringListWrap();
			_textLines = new List<KeyValuePair<Point, string>>();
			_textLines.Add(new KeyValuePair<Point, string>(new Point(), CreateTopBorder()));
			if (Size.Width <= 2 || Size.Height <= 2)
				return;
			int lineWidth = Size.Width - 1;

			
			for (int i = 0; i < Size.Height - 2; i++)
			{

				Point linePoint = new Point(_textStartPos.X + i * _lineShift.X, _textStartPos.Y + i * _lineShift.Y);
				string currentLine = "";

				if ((i + 1) * lineWidth < _text.Length)
					currentLine = _text.Substring(i * lineWidth, lineWidth);
				else
					if (i * lineWidth < _text.Length)
					currentLine = _text.Substring(i * lineWidth);
				else
					currentLine = "";

				currentLine = base.DecorationSet [BoxDrawingDecorationNames.vertical] + currentLine;
				currentLine = currentLine.PadRight(_size.Width, ' ');
				currentLine += base.DecorationSet [BoxDrawingDecorationNames.vertical];
				_textLines.Add(new KeyValuePair<Point, string>(linePoint, currentLine));
			}
			_textLines.Add(new KeyValuePair<Point, string>(new Point(0, _size.Height), CreateBottomBorder()));
		}*/

		
		
		
		
		
		
		private void CreateFinalStringList()
		{
			
			
			_textLines = new List<KeyValuePair<Point, string>>();
			_textLines.Add(new KeyValuePair<Point, string>(new Point(), CreateTopBorder()));
			if (Size.Width <= 2 || Size.Height <= 2)
				return;
			int lineWidth = Size.Width - 1;

			CreateStringListWrap(lineWidth);
			
			
			for (int i = 0; i < Size.Height - 2; i++)
			{

				
				Point linePoint = new Point(_textStartPos.X + i * _lineShift.X, _textStartPos.Y + i * _lineShift.Y);
				string currentLine = "";

				/*if ((i + 1) * lineWidth < _text.Length)
					currentLine = _text.Substring(i * lineWidth, lineWidth);
				else
					if (i * lineWidth < _text.Length)
					currentLine = _text.Substring(i * lineWidth);
				else
					currentLine = "";
				 */
				
				if(_textLinesWrap.Count > (i+_vScrollPos))
					currentLine=_textLinesWrap[i+_vScrollPos];
				
				//currentLine=String.Format(" {0} {1}", _textLinesWrap.Count,i+_vScrollPos);
				
				currentLine = base.DecorationSet [BoxDrawingDecorationNames.vertical] + currentLine;
				currentLine = currentLine.PadRight(_size.Width, ' ');
				currentLine += base.DecorationSet [BoxDrawingDecorationNames.vertical];
				_textLines.Add(new KeyValuePair<Point, string>(linePoint, currentLine));
			}
			_textLines.Add(new KeyValuePair<Point, string>(new Point(0, _size.Height), CreateBottomBorder()));
		}
		
		
		
		private void CreateStringListWrap(int lineWidth)
		{
			
			_textLinesWrap=Util.Wrap(_text,lineWidth);
		}



		internal override void Redraw()
		{
			Redraw(AbsoluteBounds);
		}


		internal void Redraw(Rectangle resRect)
		{
			if (!ConsoleExists)
				return;

			if (Location.X < 0 || Location.Y < 0)
				return;

			ConsoleColor oldForeColor = Console.ForegroundColor;
			Console.ForegroundColor = ForegroundColor;
			ConsoleColor oldBackColor = Console.BackgroundColor;
			Console.BackgroundColor = BackgroundColor;
			Point oldCursorLocation = new Point(Console.CursorLeft, Console.CursorTop);


			//DrawBackground(resRect);
			DrawText(resRect);

			Console.ForegroundColor = oldForeColor;
			Console.BackgroundColor = oldBackColor;
			Console.SetCursorPosition(oldCursorLocation.X, oldCursorLocation.Y);

		}

		private void DrawText()
		{
			DrawText(AbsoluteBounds);
			return;
			/*
			foreach (KeyValuePair<Point, string> kvp in _textLines)
			{
				Console.SetCursorPosition(Location.X + kvp.Key.X, Location.Y + kvp.Key.Y);
				Console.Write(kvp.Value);
			}  */
		}

		private void DrawText(Rectangle resRect)
		{

			Rectangle ab = AbsoluteBounds;
			Rectangle r = Rectangle.Intersect(ab, resRect);
			//this.Text = "AB:" + ab.ToString() + "       R:" + r.ToString();

			r.X += -ab.X;
			r.Y += -ab.Y;

			//this.Text += " IR:" +r.ToString() + "    " + this.Location + " " + this.Size;




			int startLine = 0;
			int endLine = _textLines.Count;
			int lineWidth = 0;
			if (_textLines.Count > 0)
				lineWidth = _textLines [0].Value.Length;


			if (r.Y > 0)
				startLine = r.Y;
			if (r.Y + r.Height < _textLines.Count)
				endLine = r.Y + r.Height;

			int startChar = 0;
			int subLen = Size.Width + 1;

			if (r.X > 0 && r.X < lineWidth)
			{
				startChar = r.X;

			}


			if ((r.X + r.Width) < lineWidth)
			{
				subLen = r.Width + 1;
			}
			else
			{
				subLen = lineWidth - startChar;
			}



			//startLine = 0;
			//endLine = _textLines.Count;
			/*startChar = 0;

			
			if (_textLines.Count>0)
				subLen = _textLines[0].Value.Length;
			else
				subLen = 0;
			 */
			for (int i = startLine; i < endLine; i++)
			{
				KeyValuePair<Point, string> kvp = _textLines [i];
				//Console.SetCursorPosition(Location.X + kvp.Key.X + startChar, Location.Y + i);
				Console.SetCursorPosition(ab.X + kvp.Key.X + startChar, ab.Y + i);
				Console.Write(kvp.Value.Substring(startChar, subLen));
			}




			/*
			foreach (KeyValuePair<Point, string> kvp in _textLines)
			{
				Console.SetCursorPosition(resRect.X, Location.Y + kvp.Key.Y);
				try
				{
					Console.Write
					(
						kvp.Value.Substring
						(
							resRect.X - Location.X,
							Math.Min
							(
								kvp.Value.Length - (resRect.X - Location.X),
								resRect.Width - (resRect.X - Location.X) + 1
							)
						)
					);
				}
				catch
				{
					Console.WriteLine("{0} {1} {2} {3} {4} {5}", this.Name, this.AbsoluteBounds, resRect,

						resRect.Width - (resRect.X - Location.X) + 1
						,

						kvp.Value.Length - (resRect.X - Location.X),
								resRect.Width - (resRect.X - Location.X) + 1



						);
				}
			  
			}  */

		}


		private void DrawBackground(Rectangle resRect)
		{
			ConsoleColor oldForeColor = Console.ForegroundColor;
			Console.ForegroundColor = BackgroundColor;
			string backgroundLine = new StringBuilder(base.DecorationSet [BoxDrawingDecorationNames.background].ToString(), resRect.Width).ToString();
			Rectangle ab = AbsoluteBounds;

			for (int j = resRect.Y; j <= resRect.Height; j++)
			{
				//Console.SetCursorPosition(Location.X + resRect.X, Location.Y + j);
				Console.SetCursorPosition(ab.X + resRect.X, ab.Y + j);
				Console.Write(backgroundLine);
			}
			Console.ForegroundColor = oldForeColor;
		}

		private void DrawBackground()
		{

			DrawBackground(AbsoluteBounds);
			return;
			/*
			ConsoleColor oldForeColor = Console.ForegroundColor;
			Console.ForegroundColor = BackgroundColor;
			string backgroundLine = new StringBuilder(base.DecorationSet [BoxDrawingDecorationNames.background].ToString(), Size.Width).ToString();

			for (int i = 0; i <= Size.Width; i++)
			{
				for (int j = 0; j <= Size.Height; j++)
				{
					Console.SetCursorPosition(Location.X + i, Location.Y + j);
					Console.Write(base.DecorationSet [BoxDrawingDecorationNames.background]);
				}
			}

			Console.ForegroundColor = oldForeColor;
			 */
		}


		public override void Invalidate(Rectangle rect)
		{
			//look through textlines, extract substrings, paint them on console
			//for manager (main window)
			//manager will paint itself with background
			//each child of manager will invalidate rect in order of zindex
			//when panel moved, calculate invalidated rectangle and tell manager to invalidate itself and the children with that rectangle
			//if no content in rect, paint nothing
			//Window will paint background glyph always

			if (!Visible)
				return;



			if (_textLines.Count == 0)
			{
				CreateFinalStringList();
			}



			Rectangle resRect = Rectangle.Intersect(this.AbsoluteBounds, rect);



			if (resRect == Rectangle.Empty)
				return;


			if (Parent != null && Parent != TopLevelParent)
				Parent.Invalidate(resRect);

			Redraw(resRect);

			return;
			/*
			foreach (KeyValuePair<Point, string> kvp in _textLines)
			{


				if (
					kvp.Key.Y + Location.Y >= resRect.Y &&
					kvp.Key.Y + Location.Y <= resRect.Y + resRect.Height &&
					kvp.Key.X + Location.X + kvp.Value.Length >= resRect.X &&
					kvp.Key.X + Location.X <= resRect.X + resRect.Width

					)
				{


					Console.SetCursorPosition(resRect.X, Location.Y + kvp.Key.Y);
					Console.Write(

					kvp.Value.Substring(
						resRect.X - Location.X,
						Math.Min(
						kvp.Value.Length - (resRect.X - Location.X),
						resRect.Width - (resRect.X - Location.X) + 1

						)

						));

					//Redraw();

				}

			}
			 */



		}




		public override BoxDrawingDecorationSet DecorationSet
		{
			get { return base.DecorationSet; }
			set
			{
				base.DecorationSet = value;
				CreateFinalStringList();

			}
		}






		public override Rectangle ContentRect
		{
			get
			{
				/*
				if (_textLines.Count > 0)
					return new Rectangle(1, 1, _textLines [0].Value.Length, _textLines.Count);
				 */
				if (_textLinesWrap.Count > 0)
					return new Rectangle(1, 1, _textLinesWrap [0].Length, _textLinesWrap.Count);
				
				
				return Rectangle.Empty;
			}
		}

		
		private bool _hasScrollBar=false;
		public virtual bool HasScrollBar
		{
			get
			{
				return _hasScrollBar;
			}
			set
			{
				
				if(value && !_hasScrollBar)
				{
					_hasScrollBar=value;
					MakeScrollBars(ConsoleExists);
				}
				else if(!value && _hasScrollBar)
				{
					RemoveScrollBars();
				}
				_hasScrollBar=value;
			}
			
		}
		
		
		
		public  virtual void RemoveScrollBars()
		{
			if(this.Controls.Contains(_vScroll))
				this.Controls.Remove(_vScroll);
		}
		
		public  virtual void MakeScrollBars(bool consoleExists)
		{
			if(!HasScrollBar)
				return;
			
			_vScroll = new Scrollbar(consoleExists);
			_vScroll.ScrollbarType = ScrollbarTypes.Vertical;
			this.Controls.Add(_vScroll);
		}

		private int _vScrollPos=0;
		private int _maxVScroll=0;
		private Scrollbar _vScroll;

		public override bool ReceiveEvent(ConsoleKeyInfo cki)
		{
			
			
			Rectangle cr=ContentRect;
			//Console.WriteLine("{0} {1} {2}",cki.Key, cr.Height, Height);
			
			if(Focused || _vScroll!=null && _vScroll.Focused)
			{
				_maxVScroll=cr.Height-Height+2;
				switch(cki.Key)
				{
					case ConsoleKey.DownArrow:
						
						if(cr.Height>Height-2)
						{
							if(_vScrollPos<_maxVScroll)
							{
								_vScrollPos++;
								if(HasScrollBar)
									_vScroll.SetPosition(_vScrollPos,_maxVScroll);
								CreateFinalStringList();
								Invalidate(true);
							}
						}
						break;
					case ConsoleKey.UpArrow:
						if(cr.Height>Height-2)
						{
							
							
							if(_vScrollPos>0)
							{
								_vScrollPos--;
								if(HasScrollBar)
									_vScroll.SetPosition(_vScrollPos,_maxVScroll);
								
								CreateFinalStringList();
								Invalidate(true);
							}
						}
						break;
				}
				
				
			}
			return base.ReceiveEvent(cki);

		}

	}

	
}
